package com.tianji.learning.service.impl;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CatalogueDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.UserNote;
import com.tianji.learning.domain.query.AdminNotesQuery;
import com.tianji.learning.domain.query.NotesQuery;
import com.tianji.learning.domain.vo.AdminNotesVO;
import com.tianji.learning.domain.vo.NotesVO;
import com.tianji.learning.mapper.UserNoteMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.IUserNoteService;
import jodd.util.StringUtil;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.utils.BeanUtils;
import com.tianji.learning.domain.dto.EditNoteDTO;
import com.tianji.learning.domain.dto.NoteDTO;
import com.tianji.learning.mapper.UserNotesRefMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.learning.domain.po.UserNotesRef;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ymm
 * =======
 * @author lang
 * >>>>>>> origin/future_integral
 * @author author
>>>>>>> furure-z
 * @since 2023-04-26
 */
@Service
@RequiredArgsConstructor
public class UserNoteServiceImpl extends ServiceImpl<UserNoteMapper, UserNote> implements IUserNoteService {

    private final UserClient userClient;

    private final SearchClient searchClient;

    private final CourseClient courseClient;

    private final ILearningLessonService learningLessonService;

    private final RabbitMqHelper rabbitMqHelper;

    private final UserNotesRefMapper userNotesRefMapper;

    /**
     * 管理端分页查询
     *
     * @param notesQuery 笔记查询参数
     * @return 分页结果
     */
    @Override
    public PageDTO<AdminNotesVO> adminQueryNotesByPage(AdminNotesQuery notesQuery) {

        // 1. 查询课程关键字
        String courseName = notesQuery.getName();
        List<Long> courseIds = null;
        if (StringUtil.isNotBlank(courseName)) {
            courseIds = searchClient.queryCoursesIdByName(courseName);
            // 判断课程是否存在
            /*if (CollUtils.isEmpty(courseIds)) {
                throw new BizIllegalException("未找到相关课程");
            }*/
        }

        // 2. 查询笔记信息
        Boolean hidden = notesQuery.getHidden();
        LocalDateTime beginTime = notesQuery.getBeginTime();
        LocalDateTime endTime = notesQuery.getEndTime();
        Page<UserNote> page = this.lambdaQuery()
                .in(StringUtil.isNotBlank(courseName), UserNote::getCourseId, courseIds)
                .eq(hidden != null, UserNote::getIsPrivate, hidden)
                .gt(beginTime != null, UserNote::getCreateTime, beginTime)
                .gt(endTime != null, UserNote::getCreateTime, endTime)
                .page(notesQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<UserNote> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        // 3. 查询笔记的用户信息
        Set<Long> userIds = records.stream().map(UserNote::getAuthorId).collect(Collectors.toSet());
        if (CollUtils.isEmpty(userIds)) {
            throw new BizIllegalException("未找到相关用户信息");
        }
        // 3.1 远程获取用户信息
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        if (CollUtils.isEmpty(users)) {
            throw new BizIllegalException("未找到相关用户信息");
        }
        Map<Long, String> userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));

        // 4. 查询课程信息
        Set<Long> pageCourseIds = records.stream().map(UserNote::getCourseId).collect(Collectors.toSet());
        if (CollUtils.isEmpty(pageCourseIds)) {
            throw new BizIllegalException("未找到相关课程信息");
        }
        // 4.1 远程获取课程信息
        Map<Long, CourseFullInfoDTO> courseMap = pageCourseIds.stream()
                .map(cId -> courseClient.getCourseInfoById(cId, true, false))
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(CourseFullInfoDTO::getId, c -> c));
        if (CollUtils.isEmpty(courseMap)) {
            throw new BizIllegalException("未找到相关课程信息");
        }

        // 5. 封装VO
        List<AdminNotesVO> list = new ArrayList<>(records.size());
        for (UserNote r : records) {
            AdminNotesVO vo = new AdminNotesVO();
            vo.setId(r.getId());

            // 设置课程相关信息
            CourseFullInfoDTO cInfo = courseMap.get(r.getCourseId()); // 获取课程信息, 包含了课程的章节信息
            vo.setCourseName(cInfo.getName());  // 设置课程信息
            Map<Long, CatalogueDTO> catalogueMap = cInfo.getChapters().stream()
                    .collect(Collectors.toMap(CatalogueDTO::getId, c -> c)); // 获取 章信息, 包含了节信息
            CatalogueDTO Chapter = catalogueMap.get(r.getChapterId()); // 获取节信息
            Map<Long, CatalogueDTO> sectionMap = Chapter.getSections().stream()
                    .collect(Collectors.toMap(CatalogueDTO::getId, c -> c));
            vo.setChapterName(Chapter.getName());   // 设置章信息
            vo.setSectionName(sectionMap.get(r.getSectionId()).getName()); // 设置节信息

            // 设置作者名
            vo.setAuthorName(userMap.get(r.getAuthorId()));
            // 设置是否是客户端隐藏笔记
            vo.setHidden(r.getIsPrivate());
            // 设置笔记创建时间
            vo.setCreateTime(r.getCreateTime());

            list.add(vo);
        }

        return PageDTO.of(page, list);
    }

    /**
     * 用户端分页查询
     *
     * @param notesQuery 笔记查询参数
     * @param isMe
     * @return 分页集合
     */
    @Override
    public PageDTO<NotesVO> queryNotesByPage(NotesQuery notesQuery, boolean isMe) {
        Long userId = UserContext.getUser();
        // 判断用户是否已经购买了该课程
        boolean isBuy = queryUserAndCourseRelation(userId, notesQuery.getCourseId());
        if (!isBuy) {
            throw new BadRequestException("不能查看未购买课程的笔记");
        }
        // 1. 查询笔记分页数据
        Page<UserNote> page = this.lambdaQuery()
                //.eq(notesQuery.getOnlyMine(), UserNote::getAuthorId, userId)
                .eq(isMe, UserNote::getAuthorId, userId) // 只查询出当前登录用户的笔记

                .eq(!isMe, UserNote::getStatus, false) // 当查询所有笔记时, 只查询出公开的笔记
                .eq(!isMe, UserNote::getIsGathered, false) // 查询所有笔记时, 只能查询出不是采集的笔记

                .eq(UserNote::getIsPrivate, false) // 只查询出管理员没有隐藏的笔记
                .eq(notesQuery.getCourseId() != null, UserNote::getCourseId, notesQuery.getCourseId())
                .eq(notesQuery.getSectionId() != null, UserNote::getSectionId, notesQuery.getSectionId())
                .page(notesQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<UserNote> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        // 2. 根据笔记记录的用户id查询用户信息
        Set<Long> userIds = records.stream().map(UserNote::getAuthorId).collect(Collectors.toSet());
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        if (users == null) {
            throw new BizIllegalException("没有找到笔记相关用户!");
        }
        Map<Long, UserDTO> userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));

        // 3. 封装VO
        List<NotesVO> list = new ArrayList<>(records.size());
        for (UserNote r : records) {
            NotesVO vo = new NotesVO();
            // 设置属性
            vo.setId(r.getId());
            vo.setContent(r.getContent()); // 笔记内容
            vo.setIsPrivate(r.getIsPrivate()); // 是否是隐藏笔记 1:隐藏 0:不隐藏
            vo.setIsGathered(r.getIsGathered()); // 是否是引用的笔记 1:是 0:不是
            // 用户相关属性
            vo.setAuthorId(r.getAuthorId()); // 用户id
            UserDTO userInfo = userMap.get(r.getAuthorId());
            vo.setAuthorName(userInfo.getName()); // 用户昵称
            vo.setAuthorIcon(userInfo.getIcon()); // 用户头像url
            // 笔记创建时间
            vo.setCreateTime(r.getCreateTime());
            // 点赞数
            vo.setLikedTimes(r.getLikedTimes());
            // 播放进度
            vo.setNoteMoment(r.getNoteMoment());
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    private boolean queryUserAndCourseRelation(Long userId, Long courseId) {
        Optional<LearningLesson> learningLesson = learningLessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .oneOpt();
        return learningLesson.isPresent();
    }


    /**
     * 新增笔记
     *
     * @param dto
     */
    @Override
    public void createNote(NoteDTO dto) {
        Long userId = UserContext.getUser();
        Long courseId = dto.getCourseId();
        Long chapterId = dto.getChapterId();
        Long sectionId = dto.getSectionId();
        if (courseId == null || chapterId == null || sectionId == null) {
            throw new BizIllegalException("课程章节id信息不全！");
        }

        UserNote po = new UserNote();
        po.setCourseId(courseId);
        po.setChapterId(chapterId);
        po.setSectionId(sectionId);
        po.setContent(dto.getContent());
        po.setIsPrivate(dto.isPrivate());
        po.setNoteMoment(dto.getNoteMoment());
        po.setAuthorId(userId);
        po.setCreateTime(LocalDateTime.now());
        po.setUpdateTime(LocalDateTime.now());

        //保存积分明细记录
        rabbitMqHelper.send(
                MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.WRITE_NOTE,
                UserContext.getUser());
        //保存
        save(po);

    }

    /**
     * 根据id编辑笔记
     *
     * @param id
     * @param dto
     */
    @Override
    public void editNoteById(Long id, EditNoteDTO dto) {
        //获取用户id
        Long userId = UserContext.getUser();
        if (id == null) {
            throw new BizIllegalException("笔记id不能未空！");
        }
        //查询笔记
        UserNote un = getById(id);
        if (!Objects.equals(un.getAuthorId(), userId)) {
            throw new BizIllegalException("不能修改别人的笔记！！！");
        }

        UserNote userNote = BeanUtils.copyBean(dto, UserNote.class);
        //修改笔记
        userNote.setId(id);
        updateById(userNote);
    }

    /**
     * 根据id删除笔记
     *
     * @param id
     */
    @Override
    @Transactional
    public void deleteNoteById(Long id) {
        //当前用户id
        Long userId = UserContext.getUser();
        if (id == null) {
            throw new BizIllegalException("笔记id不能未空！");
        }
        UserNote userNote = getById(id);
        if (userNote == null) {
            throw new BizIllegalException("笔记不存在！");
        }
        //用户id
        Long authorId = userNote.getAuthorId();
        //笔记id
        Long unId = userNote.getId();

        //判断是否是自己的笔记
        if (!userNote.getIsGathered()) {
            if (!Objects.equals(authorId, userId))
                throw new BizIllegalException("不能删除别人的笔记！");
            removeById(id);
        } else {
            throw new BizIllegalException("删除的是采集比笔记！");
        }


    }


    @Override
    @Transactional
    public void gatherNote(Long id) {
        UserNote userNote = getById(id);
        if (userNote==null){
             throw new BadRequestException("笔记不存在");
        }
        //1. 判断是否是隐藏
        if (userNote.getIsPrivate()){
            throw new BadRequestException("该笔记被隐藏");
        }
        //2. 判断是否是私人
        if (userNote.getStatus()){
            throw new BadRequestException("私人笔记");
        }
        //3. 将采集状态改为true
        //4. 采集次数加1
        boolean success= getBaseMapper().updateNote(id);
        if (!success){
            throw new BadRequestException("采集失败");
        }
        //5. 先判断是否重复采集
        QueryWrapper<UserNotesRef> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNotesRef::getUserId,UserContext.getUser())
                .eq(UserNotesRef::getNoteId,userNote.getId())
                .eq(UserNotesRef::getAuthorId,userNote.getAuthorId());
        UserNotesRef userNotesRef = userNotesRefMapper.selectOne(wrapper);
        if (userNotesRef == null) {

            UserNote newNote = BeanUtils.copyBean(userNote, UserNote.class);
            newNote.setId(null);
            newNote.setAuthorId(UserContext.getUser());
            newNote.setStatus(true);
            boolean save = save(newNote);

            if (!save){
                throw new BadRequestException("添加备份笔记失败");
            }

            //6. 中间表添加采集数据
            UserNotesRef ref = new UserNotesRef();
            ref.setNoteId(id);
            ref.setUserId(UserContext.getUser());
            ref.setAuthorId(userNote.getAuthorId());
            ref.setUserNoteId(newNote.getId());
            int insert = userNotesRefMapper.insert(ref);
            if (insert<0){
                throw new BadRequestException("添加中间表失败");
            }

        }else {
            throw new BadRequestException("重复采集");
        }

        //7. 采集添加积分
        rabbitMqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.NOTE_GATHERED,
                userNote.getAuthorId());
    }

    @Override
    @Transactional
    public void deleteGatherNote(Long id) {
        //1. 查询
        UserNote userNote = getById(id);
        if (userNote==null){
            throw new BadRequestException("笔记不存在");
        }
        //2. 引用人数-1
        boolean success = getBaseMapper().deleteNum(id);
        if (!success){
            throw new BadRequestException("修改引用次数失败");
        }
        //3. 当引用人数为0时，将是否被采集改为0
        Integer count= getBaseMapper().queryQuote_count(id);
        if (count==0){
           boolean isSuccess=  getBaseMapper().updateIs_gathered(id);
           if (!isSuccess){
               throw new BadRequestException("修改是否被采集状态失败");
           }
        }

        QueryWrapper<UserNotesRef> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNotesRef::getUserId,UserContext.getUser())
                .eq(UserNotesRef::getNoteId,userNote.getId())
                .eq(UserNotesRef::getAuthorId,userNote.getAuthorId());

        //4. 删除复制笔记记录
        UserNotesRef userNotesRef = userNotesRefMapper.selectOne(wrapper);
        Long userNoteId = userNotesRef.getUserNoteId();
        boolean remove = removeById(userNoteId);
        if (!remove){
            throw new BadRequestException("删除采集笔记失败");
        }
        //5. 删除中间表信息
         Integer result= userNotesRefMapper.delete(wrapper);
         if ( result <1){
             throw new BadRequestException("删除中间表失败");
         }
    }
}
